﻿using System;
using System.Linq;
using System.Windows.Forms;
using Common;

namespace ImageProcesser
{
    public partial class ImageProcessorForm : Form
    {
        private readonly ImageProcessApp _app = AppInstance.GetApplication();
        private readonly EventHandler _zoomFactorTrackValueChangedHandler;


        class FormMenuRegistry : IMenuRegistry
        {
            private readonly MenuStrip _menu;
            ImageProcessApp app;
            public FormMenuRegistry(MenuStrip m, ImageProcessApp ipapp)
            {
                _menu = m;
                app = ipapp;
            }

            class MenuTag
            {
                public string MenuID;
                public IProcessorPlugin Plugin;
            }

            #region IMenuRegistry Members

            public void RegisterMenuItem(string ParentMenuString, string MenuString, string MenuID, Keys shortCut, IProcessorPlugin plugin)
            {
                var parent = _menu.Items.Cast<ToolStripItem>().Where(item => item.Text == ParentMenuString).Cast<ToolStripMenuItem>().FirstOrDefault();
                if (parent == null)
                {
                    parent = new ToolStripMenuItem(ParentMenuString);
                    parent.DropDownOpening += DropDownOpening;
                    parent.DropDownClosed += DropDownClosed;
                    _menu.Items.Insert(_menu.Items.Count - 1, parent);
                }

                var itemAdded = new ToolStripMenuItem(MenuString);
                var tag = new MenuTag { MenuID = MenuID, Plugin = plugin };
                itemAdded.Tag = tag;
                itemAdded.ShortcutKeys = shortCut;
                parent.DropDownItems.Add(itemAdded);
                itemAdded.Click += itemAdded_Click;
            }

            void DropDownClosed(object sender, EventArgs e)
            {
                var item = (ToolStripMenuItem)sender;
                for (var cntItem = 0; cntItem < item.DropDownItems.Count; cntItem++)
                {
                    item.DropDownItems[cntItem].Enabled = true;
                }
            }


            void DropDownOpening(object sender, EventArgs e)
            {
                var item = (ToolStripMenuItem)sender;
                for (var cntItem = 0; cntItem < item.DropDownItems.Count; cntItem++)
                {
                    item.DropDownItems[cntItem].Enabled = app.CurrentDoc != null;
                }
            }

            void itemAdded_Click(object sender, EventArgs e)
            {
                if (app.CurrentDoc != null)
                {
                    var item = (ToolStripMenuItem)sender;
                    var tag = (MenuTag)item.Tag;
                    tag.Plugin.ProcessCommand(tag.MenuID, app.CurrentDoc);
                }
            }

            #endregion
        }

        public ImageProcessorForm()
        {
            InitializeComponent();
            _zoomFactorTrackValueChangedHandler = zoomFactorTrackBar_ValueChanged;
            zoomFactorTrackBar.ValueChanged += _zoomFactorTrackValueChangedHandler;
            foreach (var plugin in AppInstance.GetPlugins())
            {
                plugin.RegisterMenu(new FormMenuRegistry(mainMenu, _app));
            }
            if (Program.CommandLineFileName != "")
                OpenFile(Program.CommandLineFileName);
        }

        void zoomFactorTrackBar_ValueChanged(object sender, EventArgs e)
        {
            if (_app.ImageView != null)
            {
                _app.ImageView.ZoomFactor = zoomFactorTrackBar.Value;
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                OpenFile(openFileDialog.FileName);
            }
        }

        private void OpenFile(string fileName)
        {
            try
            {
                _app.CurrentDoc = new Document(fileName);
                _app.CurrentDoc.SetMaxUndoCount(5);
                InitView();
            }
            catch (Exception)
            {
                MessageBox.Show("Cannot open file \"" + fileName + "\".", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private void InitView()
        {
            if (_app.ImageView != null)
                _app.ImageView.Dispose();
            _app.ImageView = new Common.View(_app.CurrentDoc);
            _app.ImageView.ZoomFactorChanged += ImageView_ZoomFactorChanged;
            _app.ImageView.Parent = docPanel;
            _app.ImageView.Dock = DockStyle.Fill;
            _app.ImageView.ViewMode = ViewMode.BestFit;
            _app.ImageView.Cursor = new Cursor(GetType(), "curDown.cur");
        }

        void ImageView_ZoomFactorChanged(int zoom, float rate)
        {
            zoomFactorTrackBar.ValueChanged -= _zoomFactorTrackValueChangedHandler;
            if (zoom < zoomFactorTrackBar.Minimum) zoom = zoomFactorTrackBar.Minimum;
            if (zoom > zoomFactorTrackBar.Maximum) zoom = zoomFactorTrackBar.Maximum;
            zoomFactorTrackBar.Value = zoom;
            zoomFactorTrackBar.ValueChanged += _zoomFactorTrackValueChangedHandler;
            zoomRateLabel.Text = (rate * 100).ToString("F0") + "%";
        }

        private void bestFitButton_Click(object sender, EventArgs e)
        {
            if (_app.ImageView != null)
                _app.ImageView.ViewMode = ViewMode.BestFit;
        }

        private void originalSizeButton_Click(object sender, EventArgs e)
        {
            if (_app.ImageView != null)
                _app.ImageView.ViewMode = ViewMode.OriginalSize;
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new AboutBox().ShowDialog();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_app.CurrentDoc != null)
            {
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        System.Drawing.Imaging.ImageFormat format;
                        if (saveFileDialog.FileName.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase))
                            format = System.Drawing.Imaging.ImageFormat.Jpeg;
                        else if (saveFileDialog.FileName.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase))
                            format = System.Drawing.Imaging.ImageFormat.Jpeg;
                        else if (saveFileDialog.FileName.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
                            format = System.Drawing.Imaging.ImageFormat.Png;
                        else if (saveFileDialog.FileName.EndsWith(".gif", StringComparison.OrdinalIgnoreCase))
                            format = System.Drawing.Imaging.ImageFormat.Gif;
                        else if (saveFileDialog.FileName.EndsWith(".tif", StringComparison.OrdinalIgnoreCase) ||
                            (saveFileDialog.FileName.EndsWith(".tiff", StringComparison.OrdinalIgnoreCase)))
                            format = System.Drawing.Imaging.ImageFormat.Tiff;
                        else
                            format = System.Drawing.Imaging.ImageFormat.Bmp;
                        _app.CurrentDoc.GetBitmap().Save(saveFileDialog.FileName, format);
                    }
                    catch (Exception)
                    {
                        MessageBox.Show("Failed to save file, location unwritable.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    }
                }
            }
        }

        private void undoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_app.CurrentDoc != null)
            {
                _app.CurrentDoc.Undo();
                _app.ImageView.ViewMode = _app.ImageView.ViewMode;
            }
        }

        private void redoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_app.CurrentDoc != null)
            {
                _app.CurrentDoc.Redo();
                _app.ImageView.ViewMode = _app.ImageView.ViewMode;
            }
        }

        private void editMenu_DropDownOpening(object sender, EventArgs e)
        {
            redoToolStripMenuItem.Enabled = _app.CurrentDoc != null && _app.CurrentDoc.CanRedo();
            undoToolStripMenuItem.Enabled = _app.CurrentDoc != null && _app.CurrentDoc.CanUndo();
        }

        private void filterToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            var item = (ToolStripMenuItem)sender;
            for (var cntItem = 0; cntItem < item.DropDownItems.Count; cntItem++)
            {
                item.DropDownItems[cntItem].Enabled = _app.CurrentDoc != null;
            }
        }

        private void editMenu_DropDownClosed(object sender, EventArgs e)
        {
            redoToolStripMenuItem.Enabled = true;
            undoToolStripMenuItem.Enabled = true;

        }

        private void transformToolStripMenuItem_DropDownClosed(object sender, EventArgs e)
        {
            var item = (ToolStripMenuItem)sender;
            for (var cntItem = 0; cntItem < item.DropDownItems.Count; cntItem++)
            {
                item.DropDownItems[cntItem].Enabled = true;
            }
        }

        private void docPanel_DragOver(object sender, DragEventArgs e)
        {

        }

        private void docPanel_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Link : DragDropEffects.None;
        }

        private void docPanel_DragDrop(object sender, DragEventArgs e)
        {
            OpenFile(((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString());
        }
    }
}
